package httpHandler

import (
	baseAuth "gitee.com/zaiqiang231/go-base-app/base_app/auth"
	baseLog "gitee.com/zaiqiang231/go-base-app/base_app/log"
	"gitee.com/zaiqiang231/lovesport-user-service/app/config"
	"gitee.com/zaiqiang231/lovesport-user-service/app/http/service"
	"gitee.com/zaiqiang231/lovesport-user-service/app/model"
	"gitee.com/zaiqiang231/lovesport-user-service/app/model/req"
	"gitee.com/zaiqiang231/lovesport-user-service/app/store"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
	"github.com/golang-jwt/jwt/v4"
	"net/http"
	"time"
)

func LoginHandler(c *gin.Context) {
	var captchaCheckReq CaptchaCheckReq
	if err := c.ShouldBindBodyWith(&captchaCheckReq, binding.JSON); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	cache, err := GetCaptchaCache()
	if err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}
	key := c.ClientIP()
	if !CaptchaStore.Verify(captchaCheckReq.CaptchaId, captchaCheckReq.Captcha, true) {
		WriteResponse(c, http.StatusBadRequest, "验证码验证失败！", nil)
		return
	}

	jwtAuth := &baseAuth.JWTAuth{
		SigningAlgorithm: "HS256",
		Key:              []byte(config.GlobalAppConfig.JwtConfig.Key),
	}

	var authLoginInfo baseAuth.AuthLoginInfo
	err = c.ShouldBindBodyWith(&authLoginInfo, binding.JSON)
	if err != nil {
		jwtAuth.Unauthorized(c, http.StatusUnauthorized, err.Error())
		return
	}
	baseLog.Debugf("Authenticator username = %v", authLoginInfo.Username)
	user, err := store.GetDataStore().User().Get(authLoginInfo.Username)
	if err != nil {
		baseLog.Errorf("get user info fail, %v", err)
		jwtAuth.Unauthorized(c, http.StatusUnauthorized, err.Error())
		return
	}

	if user.Enable != 1 {
		baseLog.Errorf("User status failed")
		jwtAuth.Unauthorized(c, http.StatusUnauthorized, "User status failed")
		return
	}

	baseLog.Debugf("login user info = %v", user)
	if err := baseAuth.Compare(user.Password, authLoginInfo.Password); err != nil {
		baseLog.Errorf("User ComparePassword %v", err)
		jwtAuth.Unauthorized(c, http.StatusUnauthorized, "Password error")
		return
	}

	token := jwt.New(jwt.GetSigningMethod(jwtAuth.SigningAlgorithm))
	claims := token.Claims.(jwt.MapClaims)

	claims["iss"] = config.ServiceName
	claims["aud"] = config.ServiceName
	claims["sub"] = user.Name
	claims[config.AuthIdentityKey] = user.Name
	claims["iat"] = time.Now().Unix()
	claims["exp"] = time.Now().Add(config.GlobalAppConfig.JwtConfig.Timeout).Unix()

	tokenString, err := token.SignedString(jwtAuth.Key)
	if err != nil {
		baseLog.Errorf("Create token %v", err)
		jwtAuth.Unauthorized(c, http.StatusInternalServerError, "create token failed")
		return
	}

	cache.Increment(key, 1)

	WriteResponse(c, 0, "login success", gin.H{
		"token": tokenString,
		"user":  user,
	})

}

func UserCreate(c *gin.Context) {
	var req req.UserCreateReq
	if err := c.ShouldBindJSON(&req); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	validate := validator.New()
	if err := validate.Struct(req); err != nil {
		baseLog.Errorf("validate user info fail, %v", err)
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	password, err := baseAuth.Encrypt(req.Password)
	if err != nil {
		baseLog.Errorf("encrypt user pwd fail, %v", err)
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}
	req.User.Password = password

	var authorities []model.SysAuthority
	for _, v := range req.AuthorityIds {
		authorities = append(authorities, model.SysAuthority{
			AuthorityId: v,
		})
	}
	req.User.Authorities = authorities

	if err := store.GetDataStore().User().Create(&req.User); err != nil {
		baseLog.Errorf("create user fail, %v", err)
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	WriteResponse(c, 0, "success", req.User)
}

func UserGet(c *gin.Context) {
	name := c.Param("name")
	user, err := store.GetDataStore().User().Get(name)
	if err != nil {
		baseLog.Errorf("get user info fail, %v", err)
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	WriteResponse(c, 0, "get user info success", user)
}

func UserUpdate(c *gin.Context) {
	var targetUser map[string]interface{}
	if err := c.ShouldBindJSON(&targetUser); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	updateErr := service.ServiceUserInstance.Update(targetUser)
	if updateErr != nil {
		baseLog.Errorf("update user info fail, %v", updateErr)
		WriteResponse(c, http.StatusBadRequest, updateErr.Error(), nil)
		return
	}

	WriteResponse(c, 0, "success", nil)
}

func UserDelete(c *gin.Context) {
	var request req.GetById
	if err := c.ShouldBindBodyWith(&request, binding.JSON); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}
	validate := validator.New()
	if err := validate.Struct(request); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	username := c.GetString(config.AuthIdentityKey)
	user, err := store.GetDataStore().User().Get(username)
	if err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	if user.ID == request.ID {
		WriteResponse(c, http.StatusBadRequest, "不可以删除自己", nil)
		return
	}

	err = store.GetDataStore().User().Delete(request.ID, false)
	if err != nil {
		baseLog.Errorf("get user info fail, %v", err)
		WriteResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}

	WriteResponse(c, 0, "success", nil)
}

func UserSelfGet(c *gin.Context) {
	username := c.GetString(config.AuthIdentityKey)
	user, err := store.GetDataStore().User().Get(username)
	if err != nil {
		baseLog.Errorf("get user info fail, %v", err)
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	WriteResponse(c, 0, "success", user)
}

func SetUserAuthority(c *gin.Context) {
	var request req.SetUserAuth
	if err := c.ShouldBindBodyWith(&request, binding.JSON); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	validate := validator.New()
	if err := validate.Struct(request); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}
	username := c.GetString(config.AuthIdentityKey)
	user, err := store.GetDataStore().User().Get(username)
	if err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}
	err = service.ServiceUserInstance.SetUserAuthority(user.ID, request.AuthorityId)
	if err != nil {
		WriteResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}
	WriteResponse(c, 0, "success", nil)
}

func SetUserAuthorities(c *gin.Context) {
	var request req.SetUserAuthorities
	if err := c.ShouldBindBodyWith(&request, binding.JSON); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	validate := validator.New()
	if err := validate.Struct(request); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}
	err := service.ServiceUserInstance.SetUserAuthorities(request.ID, request.AuthorityIds)
	if err != nil {
		WriteResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}
	WriteResponse(c, 0, "success", nil)
}

func SetUserPassword(c *gin.Context) {
	var request req.SetUserPasswordReq
	if err := c.ShouldBindBodyWith(&request, binding.JSON); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	validate := validator.New()
	if err := validate.Struct(request); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}
	err := service.ServiceUserInstance.SetUserPassword(request.ID, request.Password)
	if err != nil {
		WriteResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}
	WriteResponse(c, 0, "success", nil)
}

func GetUserList(c *gin.Context) {
	var request req.PageInfo
	if err := c.ShouldBindBodyWith(&request, binding.JSON); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	validate := validator.New()
	if err := validate.Struct(request); err != nil {
		WriteResponse(c, http.StatusBadRequest, err.Error(), nil)
		return
	}

	list, total, err := service.ServiceUserInstance.GetUserInfoList(request)
	if err != nil {
		WriteResponse(c, http.StatusInternalServerError, err.Error(), nil)
		return
	}
	WriteResponse(c, 0, "success", gin.H{
		"list":     list,
		"total":    total,
		"page":     request.Page,
		"pageSize": request.PageSize,
	})
}
